package com.generalbackend.common.util;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONObject;
import com.generalbackend.common.exception.EToolsRuntimeException;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.net.HttpCookie;
import java.net.URLDecoder;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 会话工具类
 * 会记录一次会话中所有的cookie,并携带cookie进行访问
 * @author tim.xie
 * @date 2022/6/9 9:24
 */
@Slf4j
public class SessionUtil {

    private List<HttpCookie> cookies;

    @Getter
    @Setter
    private Map<String, String> headers;

    private static final Integer RESPONSE_SUCCESS_STATUS = 200;

    public SessionUtil(){

    }

    public SessionUtil(Map<String, String> headers) {
        this.headers = headers;
    }

    /**
     * json方式的post请求
     * @param url
     * @param json
     * @return
     */
    public String jsonPost(String url, String json) {
        log.info("进行jsonPost请求:\nurl: " + url + "\njson: " + json);
        HttpRequest request = HttpRequest.post(url)
                .body(json)
                .addHeaders(headers);
        HttpResponse response = request.execute();
        log.info("jsonPost请求响应: ", response);
        checkResponse(response);
        updateCookie(response);
        return response.body();
    }

    /**
     * 表单方式的post请求
     * @param url
     * @param formMap
     * @return
     */
    public String formPost(String url, Map<String, Object> formMap) throws EToolsRuntimeException {
        log.info("进行formPost请求:\nurl: " + url + "\nmap: " + JSONObject.toJSONString(formMap) + "\nheaders: " + JSONObject.toJSONString(headers));
        HttpRequest request = HttpRequest.post(url)
                .form(formMap)
                .addHeaders(headers);
        HttpResponse response = request.execute();
        log.info("formPost请求响应: ", response);
        checkResponse(response);
        updateCookie(response);
        return response.body();
    }

    /**
     * 表单方式的post请求,携带文件
     * @param url
     * @param formMap
     * @return
     */
    public String formPost(String url, Map<String, Object> formMap, String fileKey, File file) throws EToolsRuntimeException {
        log.info("进行formPost请求:\nurl: " + url + "\nmap: " + JSONObject.toJSONString(formMap) + "\nheaders: " + JSONObject.toJSONString(headers));
        log.info("附带文件: " + file.getAbsolutePath());
        HttpRequest request = HttpRequest.post(url)
                .form(formMap)
                .form(fileKey, file)
                .addHeaders(headers);
        HttpResponse response = request.execute();
        log.info("formPost请求响应: " + JSONObject.toJSONString(response));
        checkResponse(response);
        updateCookie(response);
        return response.body();
    }

    /**
     * get请求
     * @param url
     * @return
     */
    public String get(String url) {
        log.info("进行get请求:\nurl: " + url);
        HttpResponse response = HttpRequest.get(url)
                .addHeaders(headers)
                .execute();
        log.info("get请求响应: ", response);
        checkResponse(response);
        updateCookie(response);
        return response.body();
    }

    /**
     * 文件下载
     * @param url
     * @param dest
     * @return
     */
    public File downloadFile(String url, String dest) {
        log.info("进行downloadFile请求:\nurl: " + url + "\ndest: " + dest);
        HttpResponse response = HttpRequest.get(url)
                .addHeaders(headers)
                .execute();
        log.info("downloadFile请求响应: ", response);
        checkResponse(response);
        updateCookie(response);
        String filename = response.header("Content-Disposition").split("filename=")[1];
        File file = new File(URLDecoder.decode(dest + filename));
        response.writeBody(file);
        file.renameTo(file);
        return file;
    }

    /**
     * 更新cookies,每次请求都更新cookie
     * @param response
     */
    private void updateCookie(HttpResponse response) {
        List<HttpCookie> newCookies = response.getCookies();
        if (newCookies == null || newCookies.size() == 0) {
            return;
        }
        if (cookies == null || cookies.size() == 0) {
            cookies = newCookies;
        }
        newCookies.forEach(newCookie -> {
            cookies.forEach(cookie -> {
                if (cookie.getName().equals(newCookie.getName())) {
                    cookie.setValue(newCookie.getValue());
                }
            });
            List<String> cookieName = cookies.stream().map(map -> map.getName()).collect(Collectors.toList());
            if (!cookieName.contains(newCookie.getName())) {
                cookies.add(newCookie);
            }
        });
    }

    /**
     * 在原有基础上添加header
     * @param headers
     */
    public void addHeaders(Map<String, String> headers) {
        if (this.headers == null) {
            this.headers = headers;
        } else {
            this.headers.putAll(headers);
        }
    }

    /**
     * 重新添加header
     * @param headers
     */
    public void reAddHeaders(Map<String, String> headers) {
        this.headers = headers;
    }

    /**
     * 校验返回值
     * @param response
     */
    public void checkResponse(HttpResponse response) {
        if (response.getStatus() != RESPONSE_SUCCESS_STATUS) {
            throw new EToolsRuntimeException("请求失败 status: " + response.getStatus());
        }
    }



}
